package ca.seia.comp6521.a2.io;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.Arrays;
import java.util.StringTokenizer;

import ca.seia.comp6521.a2.itemsetalgorithms.BitVector;
import ca.seia.comp6521.a2.itemsetalgorithms.PassIIResult;
import ca.seia.comp6521.a2.itemsetalgorithms.PassIResult;
import ca.seia.comp6521.a2.itemsetalgorithms.PassNResult;
import ca.seia.comp6521.a2.itemsetstorage.IntItemCountStorage;
import ca.seia.comp6521.a2.itemsetstorage.IntItems;
import ca.seia.comp6521.a2.itemsetstorage.PairStorage;

public class DataFileReader {

	public static final String FILE_DELIMITER = " ";
	
	private String absolutefilePath;
	private BufferedReader reader;
	private int frequentSingleItemCapacity = 2000;
	
	public DataFileReader(String absolutefilePath) throws FileNotFoundException {
		this.absolutefilePath = absolutefilePath;
		this.reader = createBufferedReader(absolutefilePath);
	}
	
	private BufferedReader createBufferedReader(String filePath) throws FileNotFoundException {
		return new BufferedReader(new FileReader(this.absolutefilePath));
	}

	public DataFileReader(String absolutefilePath, int frequentSingleItemCapacity) throws FileNotFoundException {
		this(absolutefilePath);
		this.frequentSingleItemCapacity = frequentSingleItemCapacity;
	}
	
	/*
	 * Method to execute pass1
	 */
	public FileReadResult readTransactions() {
		int transactions = 0;
		int fileTransactionItemCount = 0;
		int transactionItemCount= 0;
		int biggestTransactionItemCount = 0;
		String line = null;
		int[] frequentSingleItemCount = new int[frequentSingleItemCapacity];
		long startTime = System.currentTimeMillis();
		try {
			while ((line = reader.readLine()) != null) {
				StringTokenizer tokenizer = new StringTokenizer(line, " ");
				while(tokenizer.hasMoreTokens()) {
					transactionItemCount++;
					frequentSingleItemCount[Integer.parseInt(tokenizer.nextToken())]++;
				}
				biggestTransactionItemCount = Math.max(biggestTransactionItemCount, transactionItemCount);
				fileTransactionItemCount += transactionItemCount;
				transactions++;
				transactionItemCount = 0;
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		long executionTime = System.currentTimeMillis() - startTime;
		System.out.println("phase1 execution time = " + executionTime);
		return new FileReadResult(transactions, biggestTransactionItemCount, fileTransactionItemCount/transactions, frequentSingleItemCount);
	}
	
	/**
	 *  
	 * @param passIResult
	 * @param pairStorage
	 * @throws FileNotFoundException
	 */
	public void readTransactions(PassIResult passIResult,PairStorage pairStorage) throws FileNotFoundException {
		//Pattern pattern = Pattern.compile(FILE_DELIMITER);
		this.reader = createBufferedReader(getAbsolutefilePath());
		String line = null;
		String[] items = null;
		BitVector bitVector = passIResult.getBitVector();
		int transactionItemSize = 0;
		int transactionCount = 0;
		try {
			while ((line = reader.readLine()) != null) {
//				items = pattern.split(line);
				items = line.split(FILE_DELIMITER);
				transactionCount ++;
//				System.out.println("transaction line = " + transactionCount);
				transactionItemSize = items.length;
				//System.out.println("Number of items in transaction = " + transactionItemSize);
				//System.out.println("bitVector Biggest Freuqent item = " + bitVector.getBiggestFrequentItem());
				for(int item1 = 0; item1 < transactionItemSize ; item1++) {
					int itemValue = Integer.parseInt(items[item1]);
					//System.out.println("item1 " + itemValue);
					if (itemValue > bitVector.getBiggestFrequentItem()) {
						break;
					}
					//if(bitVector.isFrequentItem(item1)) { //generate pair for this tiem
					if(bitVector.isFrequentItem(itemValue)) { //generate pair for this tiem
						for(int item2 = item1 + 1;item2 < transactionItemSize ; item2++) {
							int itemValue2 = Integer.parseInt(items[item2]);
							//System.out.println("index of item2 = " + item2);
							//System.out.println("item2  " + itemValue2);
							if (itemValue2 > bitVector.getBiggestFrequentItem()) {
								break;
							}
							//if(bitVector.isFrequentItem(item2)) {
							if(bitVector.isFrequentItem(itemValue2)) {
								//System.out.println("adding pair ( " + item1 +" , " + item2 + " ) ");
								//System.out.println("adding pair ( " + itemValue +" , " + itemValue2 + " ) ");
//								pairStorage.addCount(item1, item2);
								pairStorage.addCount(itemValue, itemValue2);
							}
						}
					}
				}
				//if(transactionCount == 1) {break;}
			}
			System.out.println("finished reading PassII transactions");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public void readTransactions(PassIIResult passIIResult,IntItemCountStorage intItemCountStorage) throws FileNotFoundException {
		this.reader = createBufferedReader(getAbsolutefilePath());
		String line = null;
		String[] items = null;
		int numberOfCandidateItemsToMatch = 3 ;//TODO get this from the passResult;
		int matchedCountIndex = 0;
		try {
			while ((line = reader.readLine()) != null) {
				items = line.split(FILE_DELIMITER);
				
				for (IntItems candidateItems : passIIResult.getCandidateTriplets()) {
					matchedCountIndex = 0;
					finishedAnalyzingCandidateItem:
					while (matchedCountIndex < numberOfCandidateItemsToMatch) {
						for (int itemIndex = 0 ; itemIndex < items.length ; itemIndex++) {
							int item = Integer.parseInt(items[itemIndex]) ;
							if (item > candidateItems.getItem(matchedCountIndex)) {
								//case where the item in the transaction is bigger then the candidate item
								break finishedAnalyzingCandidateItem;
							}
							if ( item == candidateItems.getItem(matchedCountIndex)) {
								matchedCountIndex++; 
								if(matchedCountIndex >= numberOfCandidateItemsToMatch) {
									intItemCountStorage.addCount(candidateItems);
									break finishedAnalyzingCandidateItem;
								}
							}
						}
						break finishedAnalyzingCandidateItem;
					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public void readTransactions(PassNResult passNResult,IntItemCountStorage intItemCountStorage) throws FileNotFoundException {
		this.reader = createBufferedReader(getAbsolutefilePath());
		String line = null;
		String[] items = null;
		int numberOfCandidateItemsToMatch = passNResult.getPassNumber();
		int matchedCountIndex = 0;
		try {
			while ((line = reader.readLine()) != null) {
				items = line.split(FILE_DELIMITER);
				//TODO add condition to skip candidateItem if the number of transactions has exceeded the threshlhold
				// If remaining transactions to process ( current transactionCount - TransactionTotal ) + current occurence count < support we can stop checking this candidate pair
				for (IntItems candidateItems : passNResult.getCandidateFrequentItems()) {
					matchedCountIndex = 0;
					finishedAnalyzingCandidateItem:
					while (matchedCountIndex < numberOfCandidateItemsToMatch) {
						for (int itemIndex = 0 ; itemIndex < items.length ; itemIndex++) {
							int item = Integer.parseInt(items[itemIndex]) ;
							if (item > candidateItems.getItem(matchedCountIndex)) {
								//case where the item in the transaction is bigger then the candidate item
								break finishedAnalyzingCandidateItem;
							}
							if ( item == candidateItems.getItem(matchedCountIndex)) {
								matchedCountIndex++; 
								if(matchedCountIndex >= numberOfCandidateItemsToMatch) {
									intItemCountStorage.addCount(candidateItems);
									break finishedAnalyzingCandidateItem;
								}
							}
						}
						break finishedAnalyzingCandidateItem;
					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	
	public String getAbsolutefilePath() {
		return absolutefilePath;
	}

	public void setAbsolutefilePath(String absolutefilePath) {
		this.absolutefilePath = absolutefilePath;
	}

	public BufferedReader getReader() {
		return reader;
	}

	public void setReader(BufferedReader reader) {
		this.reader = reader;
	}

}
